
library(shiny)
library(shinyAce)
library(dplyr)

init <- "df <- data.frame(
  num=1:4,
  let=LETTERS[2:5],
  rand=rnorm(4)
)
df"

ui <- shinyUI(fluidPage(
  titlePanel("shinyAce auto completion demo"),
  sidebarLayout(
    sidebarPanel(
      helpText("Modify the code chunks below and click Eval to see the plot update. 
                Use Ctrl+Space for code completion when enabled."),
      radioButtons("dataset", "Dataset: ", c("mtcars", "airquality"), inline = TRUE),
      tags$pre("  %>%"),
      aceEditor("mutate", mode = "r", value = "select(wt, mpg) \n", height = "50px"),
      tags$pre("  %>% {"),
      aceEditor("plot", mode = "r", value = "plot(.) \n", height = "50px"),
      tags$pre("  }"),
      div(actionButton("eval", "Eval"), class = "pull-right"), br(),
      checkboxInput("enableAutocomplete", "Enable AutoComplete", TRUE),
      conditionalPanel(
        "input.enableAutocomplete", 
        wellPanel(
          checkboxInput("enableLiveCompletion", "Live auto completion", TRUE),
          checkboxInput("enableNameCompletion", list("Dataset column names completion in", tags$i("mutate")), TRUE),
          checkboxInput("enableRCompletion", "R code completion", TRUE),
          checkboxInput("enableLocalCompletion", "Local text completion", TRUE)
        )
      ),
      textOutput("error")
    ),
    mainPanel(
      plotOutput("plot"),
      dataTableOutput("table")
    )
  )
))

server <- shinyServer(function(input, output, session) {
  
  # dataset Selection
  dataset <- reactive({
    eval(parse(text = input$dataset))
  })
  
  output$table <- renderDataTable({
    dataset()
  })
  
  # auto completion
  observe({
    autoComplete <- if (input$enableAutocomplete) {
      if (input$enableLiveCompletion) "live" else "enabled"
    } else {
      "disabled"
    }
    
    updateAceEditor(session, "mutate", autoComplete = autoComplete)
    updateAceEditor(session, "plot", autoComplete = autoComplete)
  })
  
  # update static auto complete list according to dataset
  observe({
    req(input$enableNameCompletion)
    comps <- list()
    comps[[input$dataset]] <- colnames(dataset())
    updateAceEditor(session, "mutate", autoCompleteList = comps)
    updateAceEditor(session, "plot", autoCompleteList = list(one = "one"))
  })
  
  # enable/disable R code completion
  mutateOb <- aceAutocomplete("mutate")
  plotOb <- aceAutocomplete("plot")
  observe({
    if (input$enableRCompletion) {
      mutateOb$resume()
      plotOb$resume()
    } else {
      mutateOb$suspend()
      plotOb$suspend()
    }
  })
  
  # enable/disable completers
  observe({
    completers <- c()
    if (input$enableLocalCompletion) {
      completers <- c(completers, "text")
    }
    if (input$enableNameCompletion) {
      completers <- c(completers, "static")
    }
    if (input$enableRCompletion) {
      completers <- c(completers, "rlang")
    }
    updateAceEditor(session, "mutate", autoCompleters = completers)
    updateAceEditor(session, "plot", autoCompleters = completers)
  })
  
  output$plot <- renderPlot({ 
    input$eval
    tryCatch({
      # clear error
      output$error <- renderPrint(invisible())
      code1 <- gsub("\\s+$", "", isolate(input$mutate))
      code2 <- gsub("\\s+$", "", isolate(input$plot))
      eval(parse(text = isolate(paste(input$dataset, "%>%", code1, "%>% {", code2, "}"))))
    }, error = function(ex) {
      output$error <- renderPrint(ex)
      NULL
    })
  })
})


shinyApp(ui, server)